package com.dhcc.util;

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECPoint;

import com.alibaba.fastjson.JSONObject;
import com.dhcc.entity.DecryptE;
import com.dhcc.entity.EncryptE;
import com.dhcc.entity.GatewayRequest;
import com.dhcc.entity.SecretE;
import com.dhcc.excetion.BussesExcetion;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.ECKeyUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.symmetric.SM4;
import lombok.extern.slf4j.Slf4j;

/**
 * @description: 国密算法工具类
 * @author: guogang
 * @date: 2020/12/14 10:54
 * @version: 1.0
 */
@Slf4j
public class SMUtils {
    static{
        try{
            Security.addProvider(new BouncyCastleProvider());
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    private static EncryptE encryptE = new EncryptE();
    private static StringBuffer sb = new StringBuffer();
    private static GatewayRequest request = new GatewayRequest();
    private static SecretE secretE = new SecretE();
    public static PrivateKey privateKey;
    public static PublicKey publicKey;
    private static SM2 sm2(ECPublicKeyParameters ecPublicKeyParameters, ECPrivateKeyParameters ecPrivateKeyParameters ){
        return new SM2(ecPrivateKeyParameters,ecPublicKeyParameters);
    }

    private static SM2 sm2(String privateKey,String publicKey){
        ECPublicKeyParameters ecPublicKeyParameters = null;
        ECPrivateKeyParameters ecPrivateKeyParameters = null;
        if(publicKey!=null){
            ecPublicKeyParameters = ECKeyUtil.toSm2PublicParams(publicKey);
        }
        if(privateKey!=null){
            ecPrivateKeyParameters = ECKeyUtil.toSm2PrivateParams(privateKey);
        }
        return new SM2(ecPrivateKeyParameters,ecPublicKeyParameters);
    }

    private static SM4 sm4(String secret){
        return new SM4(secret.getBytes());
    }

    private static String sign(SM2 sm2,String body) {
        return sm2.signHex(HexUtil.encodeHexStr(body));
    }

    private static boolean verify(SM2 sm2,String sign, String body) {
        return sm2.verify(body.getBytes(), HexUtil.decodeHex(sign));
    }

    private static String  encrypt(SM2 sm2,String body) {
        return  sm2.encryptHex(body, KeyType.PublicKey);
    }

    private static String  encrypt(SM4 sm4,String body) {
        return sm4.encryptBase64(body);  // sm4 加密用base64 前端16进制解不开
    }

    private static String decrypt(SM2 sm2,String body) {
        return  sm2.decryptStr(body, KeyType.PrivateKey);
    }

    private static String decrypt(SM4 sm4, String body) {
        return sm4.decryptStr(body, CharsetUtil.CHARSET_UTF_8);
    }

//    public static void main(String[] args) throws Exception {
//
//        //加密公钥
//        String publicKey="04AEF560A110B6C64A6921FA5B0EA273C6E35E2663ACCACF47C5B9D3B6928B543F9A6D1EE34059B42A87C5A1F1975FA62B3890A373516B233B710968B49B5DC6B8";
//        //加密私钥
//        String privateKey="09645C7D3421074B4FC9448BFB0D45D4A8FCA09ED2FC2CC45F3E98FD1F43A339";
//        //加签私钥
//        String privateAddKey="09645C7D3421074B4FC9448BFB0D45D4A8FCA09ED2FC2CC45F3E98FD1F43A339";
//        //验签公钥
//        String publicAddKey="04AEF560A110B6C64A6921FA5B0EA273C6E35E2663ACCACF47C5B9D3B6928B543F9A6D1EE34059B42A87C5A1F1975FA62B3890A373516B233B710968B49B5DC6B8";
//
//    }
    /**
     * 组请求加密数据
     */
    public static GatewayRequest reqData(EncryptE encryptE) {
        try {
            //sm4对称密钥生成
            String sm4key = Sm4Util.generateKey();
            SM4 sm4 = sm4(sm4key);
            log.info("生成SM4对称密钥【"+sm4key+"】");
            //sm2对sm4对称密钥加密
            String encrypt1 = encrypt(SMUtils.sm2(null,encryptE.getAddPubSecret()), sm4key);
            log.info("获取encodekey:["+encrypt1+"]");
            String encrypt = encrypt(sm4,encryptE.getData());
            log.info("sm4加密后的内容data:["+encrypt+"]");
            //生成发送给网关的数据
            String requestId= UUID.randomUUID().toString().replaceAll("-","");
            String timeStamp= LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));

            Map<String, String> map1 = new HashMap<>();
            String mapStr = MapSignUtil.getStrData(map1);
            log.info(("排序后签名内容signdata:[{}]"+mapStr+"\n"));

            String signStr = sign(SMUtils.sm2(encryptE.getAddSignPriKey(),null),mapStr);
            log.info("生成签名sign："+signStr);

            request.setTimeStamp(timeStamp);
            request.setRequestId(requestId);
            request.setSign(signStr);
            request.setEncodeKey(encrypt1);
            request.setEncryptAlgo("SM4");
            request.setRequestData(encrypt);
        }catch (Exception e){
            e.printStackTrace();
            throw new BussesExcetion("加签加密失败");
        }
        return request;

    }
    /**
     * 测试返回结果
     * @param
     */
    public static JSONObject respCheck(DecryptE decryptE) {
        //sm2用私钥对sm4对称密钥进行解密
        String decrypt=null;
        try {
            String enkey=decryptE.getEncodeKey();
            String decrypt1 = decrypt(SMUtils.sm2(decryptE.getAddPriSecret(),null), enkey);
            log.info("解密获取sm4对称密钥："+decrypt1);
            //sm4对内容进行解密
            SM4 sm1 = sm4(decrypt1);
            String data=decryptE.getData();//需要修改
            decrypt = decrypt(sm1, data);


//            Map<String, String> map1 = RequestBodyUtil.signBody("SM4", decryptE.getEncodeKey(), decryptE.getTimeStamp(), decryptE.getRequestId(), decryptE.getMerCode(),
//                    decryptE.getApiCode(), decryptE.getChnlCode(), decryptE.getData());
            String mapStr = "MapSignUtil.getStrData(map1)";
            log.info(("排序后签名内容sgindata:[{}]"+mapStr+"\n"));

            //验签签名
            String sign=decryptE.getSign();
            boolean bool = verify(SMUtils.sm2(null, decryptE.getAddSignPubKey()),sign,mapStr);
            if(!bool){
                log.info("验签成失败："+bool);
                throw new BussesExcetion("验签失败");
            }
            log.info("验签成功："+bool);
        }catch (Exception e){
            e.printStackTrace();
            throw new BussesExcetion("验签解密失败");
        }
        JSONObject parse = (JSONObject)JSONObject.parse(decrypt);
        return parse;

    }
   public static SecretE createSecret(){
       for (int i = 0; i <2 ; i++) {
           KeyPair pair = SecureUtil.generateKeyPair("SM2");
           privateKey = pair.getPrivate();
           publicKey = pair.getPublic();
           ECPrivateKeyParameters ecPrivateKeyParameters2 = BCUtil.toParams(privateKey);
           final BigInteger d2 = ecPrivateKeyParameters2.getD();
           ECPublicKeyParameters ecPublicKeyParameters2 = BCUtil.toParams(publicKey);
           ECPoint q2 = ecPublicKeyParameters2.getQ();
           if(i!=0) {
               //加密私钥
               secretE.setAddPriSecret(HexUtil.encodeHexStr(d2.toByteArray(),false));
               //加密公钥
               secretE.setAddPubSecret(HexUtil.encodeHexStr(q2.getEncoded(false),false));

           }else {
               //加签私钥
               secretE.setAddSignPriKey(HexUtil.encodeHexStr(d2.toByteArray(),false));
               //加签公钥
               secretE.setAddSignPubKey(HexUtil.encodeHexStr(q2.getEncoded(false),false));
           }
       }
       return secretE;
   }
}
